﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using Altbrot.Yawr.Entities;
using Altbrot.Yawr.Pls;
using System.Globalization;
using System.Threading;
using Altbrot.Yawr.Rss;
using System.ComponentModel;

namespace Altbrot.Yawr.Buslogic
{
    public class DatabaseBuslogicManager : IBuslogicManager
    {                
        private string _connectionString = string.Empty;

        public DatabaseBuslogicManager(string connectionString)
        {
            _connectionString = connectionString;
        }

        #region IBuslogicManager Members

        public event UpdateProgressMethodDelegate OnUpdateProgress;

        public List<FeedItem> GetGenreList(string url)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Category == FeedItemCategory.Genre.ToString()
                             orderby fi.Title
                             select fi;

                return new List<FeedItem>(result.Cast<FeedItem>()); 
            }
        }

        public List<FeedItem> GetGenreList(string url, FeedItemDb db)
        {
            var result = from fi in db.FeedItem
                         where fi.Category == FeedItemCategory.Genre.ToString()
                         orderby fi.Title
                         select fi;

            return new List<FeedItem>(result.Cast<FeedItem>());
        }

        public List<FeedItem> GetGenreList(string url, int offsetHours)
        {
            CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("de-AT");
            List<FeedItem> res = null;

            try
            {
                DateTime offsetDate = DateTime.Now.AddHours(-Convert.ToDouble(offsetHours));

                using (FeedItemDb Db = new FeedItemDb(_connectionString))
                {
                    var result = from fi in Db.FeedItem
                                 where fi.Category == FeedItemCategory.Genre.ToString() && fi.PubDate < offsetDate
                                 orderby fi.Title
                                 select fi;

                    res = new List<FeedItem>(result.Cast<FeedItem>()); 
                }
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = currentCulture;
            }
            return res;
        }

        public List<FeedItem> GetStationList(string genre, string url)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Category == FeedItemCategory.Station.ToString() &&
                             string.Compare(fi.Genre, genre, true) == 0
                             orderby fi.Title
                             select fi;

                return new List<FeedItem>(result.Cast<FeedItem>()); 
            }
        }

        public List<FeedItem> GetStationList(string genre, string url, FeedItemDb db)
        {
            var result = from fi in db.FeedItem
                         where fi.Category == FeedItemCategory.Station.ToString() &&
                         string.Compare(fi.Genre, genre, true) == 0
                         orderby fi.Title
                         select fi;

            return new List<FeedItem>(result.Cast<FeedItem>());
        }

        public List<FeedItem> GetStationUrls(FeedItem station, string tmpFilePath)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Category == FeedItemCategory.Station.ToString() &&
                             string.Compare(fi.Link, station.Link, true) == 0
                             select fi;

                if (result.FirstOrDefault<FeedItem>() != null)
                {
                    PLSHelper helper = new PLSHelper();
                    return helper.GetFeedItemsFormPlaylist(result.FirstOrDefault<FeedItem>().Pls);
                }
                return null; 
            }
        }

        public void UpdateGenreList(List<FeedItem> items)
        {
            CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("de-AT");

            try
            {
                using (FeedItemDb Db = new FeedItemDb(_connectionString))
                {
                    List<FeedItem> genreList = GetGenreList(string.Empty, Db);

                    foreach (FeedItem currentItem in items)
                    {
                        FeedItem found = genreList.FirstOrDefault<FeedItem>(i => string.Compare(i.Link, currentItem.Link, true) == 0);

                        if (found != null)
                        {
                            // update
                            found.Description = currentItem.Description;
                            found.Guid = currentItem.Guid;
                            found.Link = currentItem.Link;
                            found.PubDate = DateTime.Now;
                            found.Read = currentItem.Read;
                            found.Source = currentItem.Source;
                            found.Title = currentItem.Title;
                            found.Genre = currentItem.Genre;
                            found.IsFavorite = currentItem.IsFavorite;
                        }
                        else
                        {
                            // insert
                            currentItem.Id = Guid.NewGuid();
                            currentItem.Category = FeedItemCategory.Genre.ToString();
                            found.PubDate = DateTime.Now;
                            currentItem.IsFavorite = false;

                            Db.FeedItem.InsertOnSubmit(currentItem);
                        }
                    }
                    Db.SubmitChanges(); 
                }
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = currentCulture;
            }
        }

        public void UpdateStation(FeedItem station)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Id == station.Id
                             select fi;

                FeedItem found = result.FirstOrDefault<FeedItem>();
                if (found != null)
                {
                    // update
                    found.Description = station.Description;
                    found.Guid = station.Guid;
                    found.Link = station.Link;
                    found.PubDate = DateTime.Now;
                    found.Read = station.Read;
                    found.Source = station.Source;
                    found.Title = station.Title;
                    found.Category = station.Category;
                    found.Genre = station.Genre;
                    found.Pls = station.Pls;
                    found.IsFavorite = station.IsFavorite;
                }
                Db.SubmitChanges(); 
            }
        }

        public void UpdateStationList(List<FeedItem> items, string genre, string tmpFilePath, AsyncOperation asyncOp)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                List<FeedItem> stationList = GetStationList(genre, string.Empty, Db);
                float count = stationList.Count;
                float index = 0;

                foreach (FeedItem currentItem in stationList)
                {
                    UpdateProgressMethod(string.Format("Checking Stations\n{0}...{1}", currentItem.Title.Substring(0, 10), "ok"), Convert.ToInt32(((index / count) * 100)), asyncOp);

                    FeedItem found = items.FirstOrDefault<FeedItem>(i => string.Compare(i.Link, currentItem.Link, true) == 0);
                    if (found == null)
                    {
                        Db.FeedItem.DeleteOnSubmit(currentItem);
                    }

                    index++;
                }

                Db.SubmitChanges();
                UpdateProgressMethod(string.Format("Deleting Stations"), 100, asyncOp);

                count = items.Count;
                index = 0;
                foreach (FeedItem currentItem in items)
                {                    
                    FeedItem found = stationList.FirstOrDefault<FeedItem>(i => string.Compare(i.Link, currentItem.Link, true) == 0);
                    PLSHelper helper = new PLSHelper();

                    if (found != null)
                    {
                        // update
                        found.Description = currentItem.Description;
                        found.Guid = currentItem.Guid;
                        found.Link = currentItem.Link;
                        found.PubDate = DateTime.Now;
                        found.Read = currentItem.Read;
                        found.Source = currentItem.Source;
                        found.Title = currentItem.Title;
                        found.Category = FeedItemCategory.Station.ToString();
                        found.Genre = genre;
                        found.Pls = helper.GetPlsStringFromPlaylist(found.Link, tmpFilePath);
                        found.IsFavorite = currentItem.IsFavorite;

                        UpdateProgressMethod(string.Format("Updating Stations\n{0}...{1}", currentItem.Title.Substring(0, 10), "updated"), Convert.ToInt32(((index / count) * 100)), asyncOp);
                    }
                    else
                    {
                        // insert
                        currentItem.Id = Guid.NewGuid();
                        currentItem.Category = FeedItemCategory.Station.ToString();
                        currentItem.Genre = genre;
                        currentItem.Pls = helper.GetPlsStringFromPlaylist(currentItem.Link, tmpFilePath);
                        currentItem.IsFavorite = false;
                        currentItem.PubDate = DateTime.Now;
                        Db.FeedItem.InsertOnSubmit(currentItem);

                        UpdateProgressMethod(string.Format("Updating Stations\n{0}...{1}", currentItem.Title.Substring(0, 10), "added"), Convert.ToInt32(((index / count) * 100)), asyncOp);
                    }
                    index++;
                }
                Db.SubmitChanges();
                UpdateProgressMethod(string.Format("Updating Stations"), 100, asyncOp);
            }
        }

        /// <summary>
        /// Searches the specified expression.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        public List<FeedItem> Search(string expression)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Title.Contains(expression) ||
                             fi.Description.Contains(expression)
                             orderby fi.Title
                             select fi;

                return new List<FeedItem>(result.Cast<FeedItem>()); 
            }
        }

        /// <summary>
        /// Gets the custom list.
        /// </summary>
        /// <returns></returns>
        public List<FeedItem> GetFavoritesList()
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Category == FeedItemCategory.Station.ToString() &&
                             fi.IsFavorite != null && fi.IsFavorite == true
                             orderby fi.Title
                             select fi;

                return new List<FeedItem>(result.Cast<FeedItem>()); 
            }
        }

        /// <summary>
        /// Sets the favorite.
        /// </summary>
        /// <param name="id">The id.</param>
        public void ToggleFavorite(Guid id)
        {
            using (FeedItemDb Db = new FeedItemDb(_connectionString))
            {
                var result = from fi in Db.FeedItem
                             where fi.Id == id
                             select fi;
                FeedItem found = result.FirstOrDefault<FeedItem>();
                if (found != null)
                {
                    if (found.IsFavorite == null)
                        found.IsFavorite = false;

                    found.IsFavorite = !found.IsFavorite;

                    Db.SubmitChanges();
                } 
            }
        }

        #endregion

        private void UpdateProgressMethod(string message, int progress, AsyncOperation asyncOp)
        {
            if (this.OnUpdateProgress != null && asyncOp != null)
                OnUpdateProgress(message, progress, asyncOp);
        }
    }

    public static class Extensions
    {
        public static bool Exists(this List<FeedItem> list, FeedItem item)
        {
            return list.Any<FeedItem>(i => string.Compare(i.Link, item.Link, true) == 0);
        }
    }    
}
